/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package org.knolle.proveedorServicios;


import java.io.*;
import java.math.BigDecimal;
import java.util.Arrays;
import java.util.List;
import org.marcelo.agro.entidades.*;
import org.hibernate.criterion.Order;
import org.hibernate.criterion.Restrictions;
import org.marcelo.agro.core.DynamicLookup;
import org.marcelo.comun.file.FilesHelper;
import org.marcelo.agro.core.api.ILotes;
import org.marcelo.agro.entidades.eventos.LotesEvent;
import org.marcelo.comun.eventos.NodeEvent;
import org.openide.util.lookup.ServiceProvider;

/**
 *
 * @author marcelo
 */

@ServiceProvider(service = ILotes.class)
public class LotesDatabase  extends DefaultDatabase<Lotes>  implements ILotes{

    
    
    private String PATH_TO_INIT_FILE = System.getProperty("user.dir")+ File.separator +  "ProveedorServicios" + File.separator + "src";
    private String FILE_TO_OPEN= "lotes.sql";
    private final String tableName = "lotes";
    
    //El maximo valor que puede tener un lote esta limitado a la superficie terreste
    //El minimo valor que puede tener es cero
    //Todos los valores estan basados en el metro cuadrado, no hay valores inferiores para este sistema
    
   
    
    @Override
    public List<Departamento> getDepartamentos()  {
//        try {
            return getAllObjects(Departamento.class, Order.asc(DEFAULT_ORDEN));
//        }
//        catch (Exception e) {
//            Notificaciones.notificar(MENSAJE_ERROR_CONSULTA, e.toString());
//        }
//        return new ArrayList<Departamento>();
    }

    @Override
    public List<Distrito> getDistritos(Departamento departamento)  {
//        try {
            return getFilteredObjects(Distrito.class,
                Arrays.asList(Restrictions.eq("departamento", departamento)), 
                Order.asc("nombre"));
//        }
//        catch (Exception e) {
//            Notificaciones.notificar(MENSAJE_ERROR_CONSULTA, e.toString());
//        }
//        return new ArrayList<Distrito>();
    }

    @Override
    public List<Distrito> getDistritos()  {
//        try{
            return getAllObjects(Distrito.class, Order.asc("nombre"));
//        }
//        catch (Exception e) {
//            Notificaciones.notificar(MENSAJE_ERROR_CONSULTA, e.toString());
//        }
//        return new ArrayList<Distrito>();
    }

      
    /**
     * Este metodo debe verificar el nombre del Lote, y tmabien el ID, para comprobar que un lote es unico
     * debo comparar su Nombre y si encuentra algo, comparar el del objeto local con el ID de la base de datos
     * si el id es el mismo sigue siendo unico, si el id no es igua ya es un objeto repetido
     * 
     */
     
    @Override
    public Boolean esUnico(Lotes object)  {
       
        
        List<Lotes> resultList = find(object);
        if (resultList != null) {
           if (resultList.size() > 0)
            if (null != object.getId() &&  object.getId().equals(resultList.get(0).getId())){
                return true;
            }
            else {
                return false;
            }
        }
        return true;
    }

    

    

    @Override
    public List<Lotes> search(Lotes object) {
//        try{
            return searchObjectsLike(object, Order.asc(DEFAULT_ORDEN));
//        }
//        catch (Exception e) {
//            Notificaciones.notificar(MENSAJE_ERROR_CONSULTA, e.toString());
//        }
//        return new ArrayList<Lotes>();
        
    }

    

    @Override
    public List<Lotes> find(Lotes object)  {
        return getFilteredObjects(Lotes.class, 
                 Arrays.asList(Restrictions.eq("nombre", object.getNombre())), 
                 Order.asc(DEFAULT_ORDEN));
    }

//    @Override
//    public List<Lotes> getAll() {
//        return GenericManager.getAllObjects(modelo.Lotes.class, Order.asc("id"));
//    }

//    @Override
//    public void OpenSession() {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }

//    @Override
//    public void closeSession() {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }

   

//    @Override
//    public List find(Object object) {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }

//    @Override
//    public List search(Object object) {
//        throw new UnsupportedOperationException("Not supported yet.");
//    }

    @Override
    public List<Lotes> getAll() {
        return getAll(Lotes.class);
    }

    @Override
    public Integer count() {
        return getCount(Lotes.class);
    }
    
    /**
     * Primero obtener la lista de lotesPorCampanas para saber si el lote esta asociado a una campana
     * Si esta asociado lanzar la excepcion,
     * Segundo obtener la lista de Actividades para este lote si tiene actividades lanzar la excepcion
     * sino proceder a borrar
     * @param object
     * @throws Exception 
     */
    @Override
    public void delete(Lotes object) throws Exception{
        
        
        
        if (countLotesPorCampanias(object) > 0) {
           throw new Exception("El elemento esta asociado a una o mas Campañas y no puede ser borrado hasta que elimine estas asociaciones");
        }
        else if (countActividades(object) > 0) {
            throw new Exception("El elemento esta asociado a una o mas Actividades y no puede ser borrado hasta que elimine estas asociaciones");
        }
        else{
          
            super.delete(object);
            LotesEvent le = new LotesEvent(NodeEvent.TIPOS_EVENTO.DELETED);
            //Notificar
            DynamicLookup.getDefault().add(le);
            //Remover la notificacion
            DynamicLookup.getDefault().remove(le);          
        }
        
    }

    @Override
    public List<LotesPorCampana> getLotesPorCampanas(Lotes lote) {
//        try {
            return getFilteredObjects(
                LotesPorCampana.class, Arrays.asList(Restrictions.eq("lotes", lote)) , 
                Order.asc(DEFAULT_ORDEN));
//        }
//        catch (Exception e) {
//            Notificaciones.notificar(MENSAJE_ERROR_CONSULTA, e.toString());
//        }
//        return new ArrayList<LotesPorCampana>();
    }

    @Override
    public List<Actividades> getActividades(Lotes lote) {
//        try {
            return getFilteredObjects(
                Actividades.class, Arrays.asList(Restrictions.eq("lotes", lote)) , 
                Order.asc(DEFAULT_ORDEN));
//        }
//        catch (Exception e) {
//            Notificaciones.notificar(MENSAJE_ERROR_CONSULTA, e.toString());
//        }
//        return new ArrayList<Actividades>();
    }

    @Override
    public Integer countLotesPorCampanias(Lotes lote) {
        return getLotesPorCampanas(lote).size();
    }

    @Override
    public Integer countActividades(Lotes lote)  {
        return getActividades(lote).size();
    }

    @Override
    public Boolean esUnico(String nombre) {
        Lotes lote = new Lotes();
        lote.setNombre(nombre);
        List<Lotes> result = find(lote);
        if (result != null) {
            if (result.size() > 0) {
                return false;
            }
        }
        return true;
    }

    @Override
    public Boolean initBBDD() throws Exception{
    /* 
     * En codigo para inicializar los datos se debe cargar un archivo del recurso
     * Una vez cargado el archivo se itera y se insertan los datos en la BBDD
     */
     File inicilizarLote = new File(PATH_TO_INIT_FILE , FILE_TO_OPEN);
        if (inicilizarLote.exists()) {
            /* Llamada desde fuera de NetBeans */
            try {
                FilesHelper filesHelper = new FilesHelper(inicilizarLote);
                String line ;
                int currentLine = 1;
                while( (line = filesHelper.getBuffReader().readLine()) != null) {
                    if (line.length() > 0 && !line.startsWith("--")) {
                        //La linea se puede agregar
                        line.trim();
//                        GenericManager.executeSql(line);
                        currentLine++;
                    }
                }
            
            }
            catch (FileNotFoundException fileNotFoundException) { }
            catch (UnsupportedEncodingException encodingException) {}
            catch (IOException ioe) {}
            finally {}
        }
        return false;
    }

    
    @Override
    public boolean saveCSVtoLote(File file) throws Exception{
    
        return saveCsvToTable(tableName, file);
    
    }

    @Override
    public boolean saveLoteToCsv(File file) throws Exception {
        return saveTableToCSV(tableName, file);
    }

    @Override
    public void saveOrUpdate(Lotes object) throws Exception {
        LotesEvent le ;
       
        if ( object.getId() != null &&  object.getId() > 0 ) {
            le = new LotesEvent(LotesEvent.TIPOS_EVENTO.EDITED);
        }
        else {
            le = new LotesEvent(LotesEvent.TIPOS_EVENTO.CREATED);
        }
        object.setSuperficie(supertificeAfundamental(object.getSuperficie(), object.getUnidadMedidaSuperficie().getFactorMultiplicacion())) ;
        super.saveOrUpdate(object);
        //Notificar
        DynamicLookup.getDefault().add(le);
        //Remover la notificacion
        DynamicLookup.getDefault().remove(le);
        
    }

    @Override
    public void saveOrUpdates(Object[] objects) throws Exception {
        super.saveOrUpdates(objects);
        
        LotesEvent le = new LotesEvent(NodeEvent.TIPOS_EVENTO.CREATED);
        //Notificar
        DynamicLookup.getDefault().add(le);
        //Remover la notificacion
        DynamicLookup.getDefault().remove(le);
        
    }
    
    private static final Integer PROPIOS = 1;
    private static final Integer ALQUILADOS = 0;
    @Override
    public Integer countLotesPropios() {
        
        return countLotes(PROPIOS);
    }

    @Override
    public Integer countLotesAlquilados() {
        return countLotes(ALQUILADOS);
    }
    
    
    private Integer countLotes(Integer estado)  {
        String criterio = "SELECT COUNT(lote.id) FROM Lotes lote WHERE lote.esPropio = " + estado;
        List<Long> result = getListEnBaseACriterio(criterio);
        if (!result.isEmpty()) {
            return result.get(0).intValue();
        }
        return 0;
            
        
    }

    @Override
    public BigDecimal supertificeAfundamental(BigDecimal superficie, BigDecimal factorMultiplicacion)  {
        int precision1 = superficie.precision();
        int presicion2 = factorMultiplicacion.precision();
        if ((precision1 + presicion2 ) > MAX_PRECISION_SUPERFICIE) {
//             "La precision supera la capacidad del sistema" ;
        }
        superficie = superficie.multiply(factorMultiplicacion, MATH_CONTEXT_UNLIMITED );
        //Antes de Guardar verificar la presicion
        if (superficie.compareTo(MAX_VALUE) > 0   ) {
//            Arrojar excepcion
//            throw new Exception("El valor supera el limite maximo");
            superficie = MAX_VALUE;
        }
        else if (superficie.compareTo(MIN_VALUE) < 0 ) {
//            Arrojar Excepcion
//            throw new Exception("El valor supera el limite minimo");
             superficie = BigDecimal.ZERO;
        }
        
        return superficie;
    }

    @Override
    public BigDecimal fundamentalAsuperficie(BigDecimal superficie, BigDecimal factorMultiplicacion)  {
        
        superficie = superficie.divide(factorMultiplicacion, SUPERFICIE_MATH_CONTEXT);
        return superficie;
    }

    @Override
    public UnidadMedidaSuperficie getUnidadSuperficieById(int id) {
        
//        try {
            return getObjectById(UnidadMedidaSuperficie.class, id);
//        }
//         catch (Exception e) {
//            String errorEn = "getUnidadSuperficieById(int Id)"; 
//            Notificaciones.notificar(MENSAJE_ERROR_CONSULTA,errorEn + e.toString());
//        }
//        return null;
       
    } 
}
